details-diagram.ts ➔ transformDiagramElement   A
last analyzed

Complexity

Conditions 2

Size

Total Lines 3
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 2
1
import { TreeStructure } from './details-mappers';
2
import { hierarchy, HierarchyPointLink, HierarchyPointNode, tree } from 'd3-hierarchy';
3
import { create, linkHorizontal } from 'd3';
4
import { Colors } from '../utils/AppConsts';
5
6
const VERTICAL_DISTANCE_BETWEEN_NODES = 40;
7
const HORIZONTAL_DISTANCE_BETWEEN_NODES = 300;
8
const NODE_NEIGHBOURS_SEPARATION_MULTIPLIER = 1;
9
const NODE_NORMAL_SEPARATION_MULTIPLIER = 4;
10
11
export function createTree(data: TreeStructure) {
12
    const node = hierarchy(data);
13
    return tree<TreeStructure>()
14
        .nodeSize([VERTICAL_DISTANCE_BETWEEN_NODES, HORIZONTAL_DISTANCE_BETWEEN_NODES])
15
        .separation((node1, node2) =>
16
            node1.parent === node2.parent ? NODE_NEIGHBOURS_SEPARATION_MULTIPLIER : NODE_NORMAL_SEPARATION_MULTIPLIER
17
        )(node);
18
}
19
20
export function getRootYPosition(data: HierarchyPointNode<TreeStructure>) {
21
    let x0 = Infinity;
22
    data.each(node => {
23
        if (node.x < x0) x0 = node.x;
24
    });
25
    return VERTICAL_DISTANCE_BETWEEN_NODES - x0;
26
}
27
28
export function createDiagram(
29
    tree: HierarchyPointNode<TreeStructure>,
30
    containerWidth: number,
31
    containerHeight: number,
32
    rootNodeYOffset: number,
33
    drawToLeft: boolean = false
34
) {
35
    if (!tree.children || !tree.children.length) {
36
        return null;
37
    }
38
39
    const diagramWidth = containerWidth / 2;
40
    const diagramXOffset = -diagramWidth / 8;
41
    const diagramYOffset = -containerHeight / 2;
42
43
    const svg = create('svg').attr('viewBox', `${diagramXOffset} ${diagramYOffset + rootNodeYOffset} ${diagramWidth} ${containerHeight}`);
44
45
    const g = svg
46
        .append('g')
47
        .attr('font-size', 15)
48
        .attr('transform', transformDiagramElement(0, rootNodeYOffset, drawToLeft));
49
50
    g.append('g')
51
        .attr('fill', 'none')
52
        .attr('stroke', Colors.ANCHOR_BLUE)
53
        .attr('stroke-width', 2)
54
        .selectAll('path')
55
        .data(tree.links())
56
        .join('path')
57
        .attr(
58
            'd',
59
            linkHorizontal<HierarchyPointLink<TreeStructure>, HierarchyPointNode<TreeStructure>>()
60
                .x(d => d.y)
61
                .y(d => d.x)
62
        );
63
64
    const node = g
65
        .append('g')
66
        .attr('stroke-linejoin', 'round')
67
        .attr('stroke-width', 3)
68
        .selectAll('g')
69
        .data(tree.descendants())
70
        .join('g')
71
        .attr('transform', d => transformDiagramElement(d.y, d.x, drawToLeft));
72
73
    node.append('text')
74
        .attr('dy', '0.31em')
75
        .attr('x', 0)
76
        .attr('text-anchor', 'middle')
77
        .style('background-color', '#ffffff')
78
        .text(node => node.data.name)
79
        .clone(true)
80
        .lower()
81
        .attr('stroke-width', 4)
82
        .attr('stroke', 'white');
83
84
    return svg;
85
}
86
87
function transformDiagramElement(xOffset: number, yOffset: number, drawToLeft: boolean) {
88
    return `translate(${xOffset},${yOffset}) ${drawToLeft ? 'rotate(180)' : ''}`;
89
}
90